import { Injectable, NotFoundException } from '@nestjs/common';
import { In, Like, Not, Repository, SelectQueryBuilder } from 'typeorm';
import { difference, filter, includes, isEmpty, map } from 'lodash';
import {
  PageSearchRoleDto,
  RoleDto,
  RoleListDto,
} from '../../dto/role/role.dto';
import { Role } from '../../entities/role.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { FindManyOptions, FindOneOptions } from 'typeorm';

import { RoleMenu } from '../../entities/role-menu.entity';
import { User } from '../../entities/user.entity';
import { MenuService } from '../menu/menu.service';

@Injectable()
export class RoleService {
  async onModuleInit() {
    if (await this.findOneByAccount('admin')) return;

    // 初始化系统管理员

    const adminRole = this.roleRepository.create({
      roleName: '超级管理员角色',
      roleCode: 'admin',
      remark: '超级管理员角色',
    });

    await this.roleRepository.save(adminRole);
  }
  constructor(
    @InjectRepository(Role)
    private readonly roleRepository: Repository<Role>,
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    private readonly menuService: MenuService,
    @InjectRepository(RoleMenu)
    private roleMenuRepository: Repository<RoleMenu>,
  ) {}
  /**
   * 通过登录账号查询用户
   *
   * @param account 登录账号
   */
  async findOneByAccount(roleCode: string): Promise<Role> {
    const role = await this.roleRepository.findOne({
      where: {
        roleCode,
      },
    });
    return role;
  }
  async create(createRoleDto: RoleListDto): Promise<Role> {
    createRoleDto.remark = createRoleDto.remark || '';
    const role = this.roleRepository.create(createRoleDto);
    return await this.roleRepository.save(role);
  }
  /**
   * 分页加载角色信息
   */
  async page(param: PageSearchRoleDto): Promise<[Role[], number]> {
    const { pageSize, pageNo, id, roleName, roleCode, remark } = param;
    const where: any = {};
    if (id) where.id = id;
    if (roleName) where.roleName = Like(`%${roleName}%`);
    if (roleCode) where.roleCode = Like(`%${roleCode}%`);
    if (remark) where.id = Like(`%${remark}%`);
    const result = await this.roleRepository.findAndCount({
      where,
      order: {
        createdTime: 'ASC',
      },
      take: pageSize,
      skip: (pageNo - 1) * pageSize,
    });

    return result;
  }
  async findAll(): Promise<any> {
    const result = await this.roleRepository.find({});

    return result;
  }
  async findOne(id: string): Promise<Role> {
    const role = await this.roleRepository.findOne({
      where: { id },
    });

    return role;
  }

  async update(updateRoleDto: RoleListDto): Promise<Role> {
    const { id } = updateRoleDto;
    const role = await this.roleRepository.findOne({
      where: { id },
    });

    this.roleRepository.merge(role, updateRoleDto);
    return await this.roleRepository.save(role);
  }

  async remove(id: string): Promise<void> {
    const role = await this.findOne(id);
    await this.roleRepository.remove(role);
  }
  // 角色id查询关联的菜单ids
  async findMenusByRoleId(roleId: string): Promise<any> {
    // const role = await this.roleMenuRepository.find({
    //   where: {
    //     roleId: In(roleId as any),
    //   },
    //   relations: ['menuId'],
    // });
    console.log(roleId, 'roleId');
    if (roleId?.length == 0) {
      return [];
    }
    const role = await this.roleMenuRepository
      .createQueryBuilder('roleMenu')
      .innerJoinAndSelect('roleMenu.menuId', 'menu')
      .where('roleMenu.roleId = :roleId', { roleId })
      .orderBy('menu.sortNo', 'ASC')
      .getMany();
    const flatMenus = role.map((val) => val.menuId);
    const ids = role.map((val) => val.id);
    // 替换为获取所有菜单的方法
    const treeList = this.menuService.buildMenuTree(flatMenus, true);
    // 提取菜单ID并返回
    // console.log(treeList,'treeList');

    return [treeList];
  }

  /**
   * 关联角色和菜单
   *
   * @param roleId
   * @param menuIds
   */
  async associateMenuWithRole(roleId: string, menuIds: string[]): Promise<any> {
    // 查找角色
    const role = await this.roleRepository.findOne({
      where: { id: roleId },
    });

    if (!role) {
      return `Role with id ${roleId} not found`;
    }

    // 删除之前关联的菜单
    await this.roleMenuRepository
      .createQueryBuilder()
      .delete()
      .from(RoleMenu)
      .where('roleId = :roleId', { roleId })
      .execute();

    // 关联新的菜单
    const roleMenusToAttach = menuIds.map((menuId) => {
      return this.roleMenuRepository.create({
        roleId: roleId as any,
        menuId: menuId as any,
      });
    });
    await this.roleMenuRepository.save(roleMenusToAttach);
    return '关联成功';
  }

  /**
   * 用于获取角色关联的菜单
   * @param roleId
   * @returns
   */

  async getMenusByRoleId(roleId: string): Promise<any> {
    const roles = await this.roleRepository.findOne({
      where: { id: roleId },
    });
    console.log(roles, 'roles');

    if (!roles) {
      return `Role with id ${roleId} not found`;
    }

    // 查找角色
    const role = await this.roleMenuRepository.find({
      where: {
        roleId: roles,
      },
      relations: ['menuId'],
    });

    // const flatMenus = role.map((val) => val.menuId);
    const ids = role.map((val) => val.menuId.id);
    const flatMenus = await this.menuService.getAllMenus();
    // 替换为获取所有菜单的方法
    const treeList = this.menuService.buildMenuTree(flatMenus, true);
    return [ids, treeList];
  }

  /**
   * 根据用户id查找角色信息
   */
  async getRoleIdByUser(userId: string): Promise<string[]> {
    // 查找角色
    const user = await this.userRepository.findOne({
      where: { id: userId },
      relations: ['roles'],
    });

    if (!isEmpty(user)) {
      return map(user, (v) => {
        return v.roleId;
      });
    }
    return [];
  }

  /**
   * 根据角色ID列表查找关联用户ID
   */
  async countUserIdByRole(ids: number[]): Promise<number | never> {
    return await this.userRepository.count({ where: { roles: In(ids) } });
  }

  async findByPage(
    page: number = 1,
    pageSize: number = 10,
    options?: FindManyOptions<Role>,
  ): Promise<[Role[], number]> {
    const [roles, count] = await this.roleRepository.findAndCount({
      ...options,
      take: pageSize,
      skip: (page - 1) * pageSize,
    });

    return [roles, count];
  }

  async findByConditions(
    conditions: Partial<Role>,
    page: number = 1,
    pageSize: number = 10,
  ): Promise<[Role[], number]> {
    const queryBuilder = this.roleRepository.createQueryBuilder('role');
    this.applyConditions(queryBuilder, conditions);
    const [roles, count] = await queryBuilder
      .take(pageSize)
      .skip((page - 1) * pageSize)
      .getManyAndCount();
    return [roles, count];
  }

  private applyConditions(
    queryBuilder: SelectQueryBuilder<Role>,
    conditions: Partial<Role>,
  ): void {
    for (const [key, value] of Object.entries(conditions)) {
      queryBuilder.andWhere(`role.${key} = :${key}`, { [key]: value });
    }
  }
}
